package com.imdada.open.platform.client.allinone.example.order;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.annotation.JSONField;
import com.github.kevinsawicki.http.HttpRequest;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * 取消追加订单代码示例 <br/>
 * 需要引入以下依赖(jdk8及以上)
 * <pre> {@code
 *    <dependency>
 *        <groupId>org.apache.commons</groupId>
 *        <artifactId>commons-lang3</artifactId>
 *        <version>3.4</version>
 *    </dependency>
 *    <dependency>
 *        <groupId>commons-codec</groupId>
 *        <artifactId>commons-codec</artifactId>
 *        <version>1.11</version>
 *    </dependency>
 *    <dependency>
 *        <groupId>ch.qos.logback</groupId>
 *        <artifactId>logback-classic</artifactId>
 *        <version>1.2.3</version>
 *    </dependency>
 *    <dependency>
 *        <groupId>org.projectlombok</groupId>
 *        <artifactId>lombok</artifactId>
 *        <version>1.16.16</version>
 *    </dependency>
 *    <dependency>
 *        <groupId>com.alibaba</groupId>
 *        <artifactId>fastjson</artifactId>
 *        <version>1.2.58</version>
 *    </dependency>
 *    <dependency>
 *        <groupId>com.github.kevinsawicki</groupId>
 *        <artifactId>http-request</artifactId>
 *        <version>6.0</version>
 *    </dependency>
 *  }</pre>
 */
@Slf4j
public class CancelAppointOrderClientExample {

    /**
     * 取消追加订单接口URL
     */
    private static final String URL = Configuration.getInstance().getHost() + "/api/order/appoint/cancel";

    public static void main(String[] args) {
        new CancelAppointOrderClientExample().execute();
    }

    private void execute() {
        // 取消追单的单号
        String originId = "originId-1637910090457";
        // 构建基本信息
        Map<String, String> body = Collections.singletonMap("order_id", originId);

        // 构建真正的api接口参数
        Map<String, Object> params = generateParams(body);

        try {
            // 执行请求
            String rpcResult = doInvoke(URL, params);

            // 处理结果
            processResponse(rpcResult);
        } catch (Exception e) {
            // 异常后的处理逻辑，可能由于网络或其他因素导致失败，建议添加重试
            log.error("执行异常，参数：{}", params, e);
        }
    }

    /**
     * 处理结果
     */
    private void processResponse(String rpcResult) {
        // 根据status判断是否执行成功
        DaDaResponse<?> response = JSON.parseObject(rpcResult, new TypeReference<DaDaResponse<?>>() {
        });
        if (Objects.nonNull(response) && Objects.equals(response.getStatus(), "success")) {
            log.info("执行成功，响应结果：{}", JSON.toJSONString(response.getResult()));
        } else {
            log.info("执行失败，响应结果：{}", rpcResult);
        }
    }

    /**
     * 执行http请求(可以根据实际情况替换为自己的HTTP请求方式)
     *
     * @param url    请求url
     * @param params 请求参数对象
     * @return 响应结果
     */
    private String doInvoke(String url, Map<String, Object> params) {
        log.info("开始执行请求, url: {}, 参数: {}", url, JSON.toJSONString(params));
        return HttpRequest.post(url)
                .header("content-type", "application/json")
                .header("accept", "application/json")
                .connectTimeout(1000)
                .readTimeout(5000)
                .send(JSON.toJSONString(params))
                .body();
    }

    /**
     * 构建真正的api接口参数
     *
     * @param body 接口的body参数内容
     * @return 构建真正的api接口参数
     */
    private Map<String, Object> generateParams(Object body) {
        String appSecret = Configuration.getInstance().getAppSecret();
        Map<String, Object> data = new HashMap<>();
        data.put("source_id", Configuration.getInstance().getSourceId());
        data.put("app_key", Configuration.getInstance().getAppKey());
        data.put("timestamp", LocalDateTime.now().atZone(ZoneId.systemDefault()).toEpochSecond());
        data.put("format", "json");
        data.put("v", "1.0");
        data.put("body", JSON.toJSONString(body));
        data.put("signature", signature(data, appSecret));
        return data;
    }

    /**
     * 生成签名(具体参考文档: http://newopen.imdada.cn/#/quickStart/develop/safety?_k=kklqac)
     */
    private String signature(Map<String, Object> data, String appSecret) {
        // 请求参数按照【属性名】字典升序排序后，按照属性名+属性值拼接
        String signStr = data.keySet().stream()
                .sorted()
                .map(it -> String.format("%s%s", it, data.get(it)))
                .collect(Collectors.joining(""));

        // 拼接后的结果首尾加上appSecret
        String finalSignStr = appSecret + signStr + appSecret;

        // MD5加密并转为大写
        return DigestUtils.md5Hex(finalSignStr).toUpperCase();
    }

    /**
     * 达达开放平台api接口-环境相关配置(请根据自己实际情况调整参数)
     */
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Configuration {

        /**
         * 达达开放平台域名(qa环境:newopen.qa.imdada.cn; 生产环境: newopen.imdada.cn, http和https都支持)
         */
        private String host;

        /**
         * 发单回调地址(接单、到店、取货、送达等消息通知，达达会通过该接口通知到商户)
         */
        private String callback;

        /**
         * 大客户id-即商户编号(账户中心-基本资料-商户编号)
         */
        private String sourceId;

        /**
         * 门店编号(门店标识，用商户账号在达达开放平台登录后，在管理中心-商户中心-门店管理中可以查看编号)
         * 实际情况下会有多个门店，这里为了方便测试，固定配置一个门店
         */
        private String shopNo;

        /**
         * 开发者登录后，在管理中心-开发助手-应用信息页面可以看到
         */
        private String appKey;

        /**
         * 开发者登录后，在管理中心-开发助手-应用信息页面可以看到
         */
        private String appSecret;

        /**
         * 请根据实际情况配置以下参数
         */
        private static Configuration INSTANCE = Configuration.builder()
                // 达达开放平台接口host(生成环境请修改为: newopen.imdada.cn)
                .host("http://newopen.qa.imdada.cn")
                // 请配置为自己的回调地址
                .callback("http://baidu.com")
                // 请配置为自己的大客户id
                .sourceId("73753")
                // 请配置为自己的门店编号
                .shopNo("11047059")
                // 请配置为自己的appKey
                .appKey("dadad0119a3f3805d67")
                // 请配置为自己的appSecret
                .appSecret("f3a9845ffbbd5b6ec5d489dfb5555846")
                .build();

        public static Configuration getInstance() {
            return INSTANCE;
        }

    }

    @Data
    @Builder
    public static class AppointOrderParam {

        @JSONField(name = "order_id")
        private String orderId;

        @JSONField(name = "transporter_id")
        private Integer transporterId;

        @JSONField(name = "shop_no")
        private String shopNo;

    }

    /**
     * 接口返回结果对象
     */
    @Data
    public static class DaDaResponse<T> {

        private String status;
        private T result;
        private Integer code;
        private String msg;

    }

}
